﻿using System;
using System.Collections.Generic;
using NHibernate;
using Neturion.Dados;
using Neturion.IRepositorios;
using NHibernate.Criterion;
using NHibernate.SqlCommand;

namespace Neturion.Repositorios
{
    public class RepositorioMovimentoFinanceiro : IRepositorioMovimentoFinanceiro
    {
        public MovimentoFinanceiro Inserir(MovimentoFinanceiro movimentoFinanceiro)
        {
            GerenciadorBDConfigs.Instance.SessaoAtual().Save(movimentoFinanceiro);
            return movimentoFinanceiro;
        }

        public MovimentoFinanceiro Atualizar(MovimentoFinanceiro movimentoFinanceiro)
        {
            MovimentoFinanceiro tmpMovimentoFinanceiro = ObterPorId(movimentoFinanceiro.MovimentoId);
            // Atribuicao dos valores do objeto da memoria para o objeto obtido no banco de dados
            tmpMovimentoFinanceiro.DataAceitacao = movimentoFinanceiro.DataAceitacao;
            tmpMovimentoFinanceiro.DataCadastro = movimentoFinanceiro.DataCadastro;
            tmpMovimentoFinanceiro.DataEmissao = movimentoFinanceiro.DataEmissao;
            tmpMovimentoFinanceiro.DataExtorno = movimentoFinanceiro.DataExtorno;
            tmpMovimentoFinanceiro.DataQuitado = movimentoFinanceiro.DataQuitado;
            tmpMovimentoFinanceiro.DataVencimento = movimentoFinanceiro.DataVencimento;
            tmpMovimentoFinanceiro.Desconto = movimentoFinanceiro.Desconto;
            tmpMovimentoFinanceiro.DescontoCofins = movimentoFinanceiro.DescontoCofins;
            tmpMovimentoFinanceiro.DescontoCssl = movimentoFinanceiro.DescontoCssl;
            tmpMovimentoFinanceiro.DescontoInss = movimentoFinanceiro.DescontoInss;
            tmpMovimentoFinanceiro.DescontoIr = movimentoFinanceiro.DescontoIr;
            tmpMovimentoFinanceiro.DescontoIss = movimentoFinanceiro.DescontoIss;
            tmpMovimentoFinanceiro.Descricao = movimentoFinanceiro.Descricao;
            tmpMovimentoFinanceiro.Documento = movimentoFinanceiro.Documento;
            tmpMovimentoFinanceiro.Historico = movimentoFinanceiro.Historico;
            tmpMovimentoFinanceiro.JurosTaxas = movimentoFinanceiro.JurosTaxas;
            tmpMovimentoFinanceiro.EnumSituacaoMovimento = movimentoFinanceiro.EnumSituacaoMovimento;
            tmpMovimentoFinanceiro.EnumTipoMovimentoFinanceiro = movimentoFinanceiro.EnumTipoMovimentoFinanceiro;
            tmpMovimentoFinanceiro.Multa = movimentoFinanceiro.Multa;
            tmpMovimentoFinanceiro.Parcelado = movimentoFinanceiro.Parcelado;
            tmpMovimentoFinanceiro.QuantidadeParcelas = movimentoFinanceiro.QuantidadeParcelas;
            tmpMovimentoFinanceiro.Valor = movimentoFinanceiro.Valor;
            tmpMovimentoFinanceiro.ValidadePagamento = movimentoFinanceiro.ValidadePagamento;
            tmpMovimentoFinanceiro.ContaContabil = movimentoFinanceiro.ContaContabil;
            tmpMovimentoFinanceiro.FonteGeradora = movimentoFinanceiro.FonteGeradora;
            tmpMovimentoFinanceiro.FormaPagamento = movimentoFinanceiro.FormaPagamento;
            tmpMovimentoFinanceiro.PessoaCredorDevedor = movimentoFinanceiro.PessoaCredorDevedor;
            tmpMovimentoFinanceiro.Setor = movimentoFinanceiro.Setor;
            tmpMovimentoFinanceiro.Usuario = movimentoFinanceiro.Usuario;

            tmpMovimentoFinanceiro.ListaTitulos.Clear();
            foreach (Titulo titulo in movimentoFinanceiro.ListaTitulos)
            {
                tmpMovimentoFinanceiro.AdicionarTitulo(titulo);
            }

            GerenciadorBDConfigs.Instance.SessaoAtual().Merge(tmpMovimentoFinanceiro);
            return tmpMovimentoFinanceiro;
        }

        public void Excluir(MovimentoFinanceiro movimentoFinanceiro)
        {
            GerenciadorBDConfigs.Instance.SessaoAtual().Delete(movimentoFinanceiro);
        }

        public IList<MovimentoFinanceiro> ObterTodos()
        {
            ICriteria criteria = GerenciadorBDConfigs.Instance.SessaoAtual().CreateCriteria(typeof(MovimentoFinanceiro));
            return criteria.List<MovimentoFinanceiro>() as List<MovimentoFinanceiro>;
        }

        public IList<MovimentoFinanceiro> ObterTodos(
            int inicio, int quantidade, int quantidadeMinima,
            EnumTipoMovimentoFinanceiro enumTipoMovimentoFinanceiro,
            string documento,
            long numeroMovimento,
            string descricao,
            EnumSituacaoMovimento enumSituacaoMovimento,
            bool parcelado,
            Pessoa credorDevedor,
            Setor setor,
            FonteGeradora fonteGeradora,
            ContaContabil contaContabil,
            DateTime? emissaoDe,
            DateTime? emissaoAte,
            DateTime? vencimentoDe,
            DateTime? vencimentoAte,
            DateTime? aceitoDe,
            DateTime? aceitoAte,
            DateTime? quitadoDe,
            DateTime? quitadoAte,
            DateTime? estornadoDe,
            DateTime? estornadoAte,
            decimal valorDe,
            decimal valorAte,
            FormaPagamento formaPagamento,
            TipoFormaPagamento tipoFormaPagamento)
        {
            if (quantidade.Equals(0))
            {
                quantidade = quantidadeMinima;
            }

            ICriteria criteria = GerenciadorBDConfigs.Instance.SessaoAtual()
                .CreateCriteria(typeof(MovimentoFinanceiro))
                .Add(Restrictions.Eq("EnumTipoMovimentoFinanceiro",enumTipoMovimentoFinanceiro))
                .SetFirstResult(inicio).SetMaxResults(quantidade);

            if (!String.IsNullOrEmpty(documento))
            {
                criteria.Add(Restrictions.Eq("Documento", documento));
            }
 
            if (numeroMovimento > 0)
            {
                criteria.Add(Restrictions.Eq("MovimentoId", numeroMovimento));
            }
                
            if (!String.IsNullOrEmpty(descricao))
            {
                criteria.Add(Restrictions.Like("Descricao", descricao, MatchMode.Anywhere));
            }

            if (enumSituacaoMovimento != EnumSituacaoMovimento.Inserindo)
            {
                criteria.Add(Restrictions.Eq("EnumSituacaoMovimento", enumSituacaoMovimento));
            }
            
            //Parcelado
            criteria.Add(Restrictions.Eq("Parcelado", parcelado));

            if (credorDevedor != null)
            {
                criteria.Add(Restrictions.Eq("PessoaCredorDevedor", credorDevedor));
            }

            if (setor != null)
            {
                criteria.Add(Restrictions.Eq("Setor", setor));
            }
             
            if (setor != null)
            {
                criteria.Add(Restrictions.Eq("Setor", setor));
            }

            if (fonteGeradora != null)
            {
                criteria.Add(Restrictions.Eq("FonteGeradora", fonteGeradora));
            }

            if (contaContabil != null)
            {
                criteria.Add(Restrictions.Eq("ContaContabil", contaContabil));
            }

            if (emissaoDe.HasValue)
            {
                criteria.Add(emissaoAte.HasValue
                                 ? Restrictions.Between("DataEmissao", emissaoDe.GetValueOrDefault().Date,
                                                        emissaoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataEmissao", emissaoDe.GetValueOrDefault().Date));
            }

            if (vencimentoDe.HasValue)
            {
                criteria.Add(vencimentoAte.HasValue
                                 ? Restrictions.Between("DataVencimento", vencimentoDe.GetValueOrDefault().Date,
                                                        vencimentoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataVencimento", vencimentoDe.GetValueOrDefault().Date));
            }

            if (aceitoDe.HasValue)
            {
                criteria.Add(aceitoAte.HasValue
                                 ? Restrictions.Between("DataAceitacao", aceitoDe.GetValueOrDefault().Date,
                                                        aceitoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataAceitacao", aceitoDe.GetValueOrDefault().Date));
            }

            if (quitadoDe.HasValue)
            {
                criteria.Add(estornadoAte.HasValue
                                 ? Restrictions.Between("DataQuitado", quitadoDe.GetValueOrDefault().Date,
                                                        estornadoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataQuitado", quitadoDe.GetValueOrDefault().Date));
            }

            if (estornadoDe.HasValue)
            {
                criteria.Add(quitadoAte.HasValue
                                 ? Restrictions.Between("DataExtorno", estornadoDe.GetValueOrDefault().Date,
                                                        quitadoAte.GetValueOrDefault().Date)
                                 : Restrictions.Eq("DataExtorno", estornadoDe.GetValueOrDefault().Date));
            }

            if (valorDe > 0)
            {
                criteria.Add(valorAte > valorDe
                                 ? Restrictions.Between("Valor", valorDe, valorAte)
                                 : Restrictions.Eq("Valor", valorDe));
            }

            if (formaPagamento != null)
            {
                criteria.CreateAlias("ListaTitulos", "Titulos")
                    .CreateAlias("Titulos.ListaPagamentos", "Pagamentos")
                    .Add(Restrictions.Disjunction()
                    .Add(Restrictions.Eq("FormaPagamento",formaPagamento))
                    .Add(Restrictions.Eq("Pagamentos.FormaPagamento", formaPagamento)));
            }
            else
            {
                if (tipoFormaPagamento != null)
                {
                    criteria.CreateAlias("ListaTitulos", "Titulos")
                       .CreateAlias("Titulos.ListaPagamentos", "Pagamentos")
                       .CreateAlias("Pagamentos.FormaPagamento", "FormaPagamentoDoPagamento")
                       .CreateAlias("FormaPagamento", "FormaPagamentoDoTitulo")
                       .Add(Restrictions.Or(
                       Restrictions.Eq("FormaPagamentoDoTitulo.TipoFormaPagamento", tipoFormaPagamento),
                       Restrictions.Eq("FormaPagamentoDoPagamento.TipoFormaPagamento", tipoFormaPagamento)));
                }
            }
            return criteria.List<MovimentoFinanceiro>() as List<MovimentoFinanceiro>;
        }

        public MovimentoFinanceiro ObterPorId(long id)
        {
            return GerenciadorBDConfigs.Instance.SessaoAtual().Get<MovimentoFinanceiro>(id);
        }
    }
}